/*
 * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <string.h>
#include <stdlib.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "at_command_handler.h"

static const char *TAG = "at_handler";

/**
 * @brief AT命令处理句柄结构体
 */
struct at_command_handler {
    usbh_cdc_handle_t cdc_handle;        /*!< USB CDC句柄 */
    char *rx_buffer;                     /*!< 接收缓冲区 */
    size_t rx_buffer_size;               /*!< 接收缓冲区大小 */
    volatile bool response_received;     /*!< 响应接收标志 */
    uint32_t default_timeout_ms;         /*!< 默认超时时间 */
    uint8_t max_retry_count;             /*!< 最大重试次数 */
    bool is_connected;                   /*!< 连接状态 */
    SemaphoreHandle_t lock;              /*!< 互斥锁 */
    at_command_response_cb_t callback;   /*!< 异步回调函数 */
    void *callback_context;              /*!< 回调上下文 */
    int itf_num;                         /*!< USB接口编号 */
};

/**
 * @brief USB连接回调函数
 */
static void at_connect_cb(usbh_cdc_handle_t cdc_handle, void *arg)
{
    at_command_handler_t handler = (at_command_handler_t)arg;
    handler->is_connected = true;
    ESP_LOGI(TAG, "AT command interface connected");
}

/**
 * @brief USB断开连接回调函数
 */
static void at_disconnect_cb(usbh_cdc_handle_t cdc_handle, void *arg)
{
    at_command_handler_t handler = (at_command_handler_t)arg;
    handler->is_connected = false;
    ESP_LOGI(TAG, "AT command interface disconnected");
}

/**
 * @brief USB数据接收回调函数
 */
static void at_recv_data_cb(usbh_cdc_handle_t cdc_handle, void *arg)
{
    at_command_handler_t handler = (at_command_handler_t)arg;
    
    // 计算可用空间
    size_t used_len = strlen(handler->rx_buffer);
    size_t available_len = handler->rx_buffer_size - used_len - 1;
    
    if (available_len > 0) {
        esp_err_t ret = usbh_cdc_read_bytes(cdc_handle, 
                                           (uint8_t*)(handler->rx_buffer + used_len), 
                                           &available_len, 
                                           0);
        if (ret == ESP_OK && available_len > 0) {
            handler->rx_buffer[used_len + available_len] = '\0';
            handler->response_received = true;
            
            // 如果设置了异步回调，则调用它
            if (handler->callback) {
                handler->callback(handler, handler->rx_buffer, used_len + available_len, handler->callback_context);
                handler->callback = NULL;
                handler->callback_context = NULL;
            }
        }
    }
}

esp_err_t at_command_create(const at_command_config_t *config, at_command_handler_t *ret_handler)
{
    // 参数检查
    if (!config || !ret_handler) {
        return ESP_ERR_INVALID_ARG;
    }

    // 分配内存
    at_command_handler_t handler = calloc(1, sizeof(struct at_command_handler));
    if (!handler) {
        ESP_LOGE(TAG, "Failed to allocate memory for AT command handler");
        return ESP_ERR_NO_MEM;
    }

    // 分配接收缓冲区
    handler->rx_buffer = calloc(1, config->rx_buffer_size);
    if (!handler->rx_buffer) {
        ESP_LOGE(TAG, "Failed to allocate memory for RX buffer");
        free(handler);
        return ESP_ERR_NO_MEM;
    }

    // 初始化参数
    handler->rx_buffer_size = config->rx_buffer_size;
    handler->default_timeout_ms = config->default_timeout_ms;
    handler->max_retry_count = config->max_retry_count;
    handler->itf_num = config->itf_num;
    handler->is_connected = false;
    handler->response_received = false;

    // 创建互斥锁
    handler->lock = xSemaphoreCreateMutex();
    if (!handler->lock) {
        ESP_LOGE(TAG, "Failed to create mutex");
        free(handler->rx_buffer);
        free(handler);
        return ESP_ERR_NO_MEM;
    }

    // 配置USB CDC设备
    usbh_cdc_device_config_t cdc_config = {
        .vid = 0,
        .pid = 0,
        .itf_num = handler->itf_num,
        .rx_buffer_size = config->rx_buffer_size,
        .tx_buffer_size = config->tx_buffer_size,
        .cbs = {
            .connect = at_connect_cb,
            .disconnect = at_disconnect_cb,
            .recv_data = at_recv_data_cb,
            .user_data = handler,
        },
    };

    // 创建USB CDC设备
    esp_err_t ret = usbh_cdc_create(&cdc_config, &handler->cdc_handle);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to create USB CDC device: %s", esp_err_to_name(ret));
        vSemaphoreDelete(handler->lock);
        free(handler->rx_buffer);
        free(handler);
        return ret;
    }

    *ret_handler = handler;
    ESP_LOGI(TAG, "AT command handler created successfully");
    return ESP_OK;
}

esp_err_t at_command_destroy(at_command_handler_t handler)
{
    if (!handler) {
        return ESP_ERR_INVALID_ARG;
    }

    // 销毁USB CDC设备
    if (handler->cdc_handle) {
        usbh_cdc_delete(handler->cdc_handle);
    }

    // 释放资源
    if (handler->lock) {
        vSemaphoreDelete(handler->lock);
    }
    
    if (handler->rx_buffer) {
        free(handler->rx_buffer);
    }
    
    free(handler);
    return ESP_OK;
}

esp_err_t at_command_send(at_command_handler_t handler, const char *command, char *response, size_t response_len, uint32_t timeout_ms)
{
    // 参数检查
    if (!handler || !command) {
        return ESP_ERR_INVALID_ARG;
    }

    // 检查连接状态
    if (!handler->is_connected) {
        ESP_LOGW(TAG, "AT command interface not connected");
        return ESP_ERR_INVALID_STATE;
    }

    // 获取互斥锁
    if (xSemaphoreTake(handler->lock, pdMS_TO_TICKS(1000)) != pdTRUE) {
        ESP_LOGE(TAG, "Failed to take mutex");
        return ESP_ERR_TIMEOUT;
    }

    // 清除之前的响应
    handler->response_received = false;
    memset(handler->rx_buffer, 0, handler->rx_buffer_size);

    ESP_LOGD(TAG, "Sending AT command: %s", command);

    // 发送命令
    size_t cmd_len = strlen(command);
    esp_err_t ret = usbh_cdc_write_bytes(handler->cdc_handle, (const uint8_t*)command, cmd_len, pdMS_TO_TICKS(1000));
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to send AT command '%s': %s", command, esp_err_to_name(ret));
        xSemaphoreGive(handler->lock);
        return ret;
    }

    // 如果需要等待响应
    if (response && response_len > 0) {
        // 使用默认超时时间如果没有指定
        if (timeout_ms == 0) {
            timeout_ms = handler->default_timeout_ms;
        }

        uint32_t timeout_ticks = pdMS_TO_TICKS(timeout_ms);
        uint32_t start_ticks = xTaskGetTickCount();

        // 等待响应
        while (!handler->response_received && (xTaskGetTickCount() - start_ticks) < timeout_ticks) {
            vTaskDelay(pdMS_TO_TICKS(10));
        }

        if (handler->response_received) {
            // 添加小延迟确保接收完整响应
            vTaskDelay(pdMS_TO_TICKS(100));
            
            // 复制响应数据
            strncpy(response, handler->rx_buffer, response_len - 1);
            response[response_len - 1] = '\0';
            ret = ESP_OK;
        } else {
            ESP_LOGW(TAG, "AT command timeout waiting for response: %s", command);
            ret = ESP_ERR_TIMEOUT;
        }
    }

    // 释放互斥锁
    xSemaphoreGive(handler->lock);
    return ret;
}

esp_err_t at_command_send_async(at_command_handler_t handler, const char *command, at_command_response_cb_t callback, void *context, uint32_t timeout_ms)
{
    // 参数检查
    if (!handler || !command) {
        return ESP_ERR_INVALID_ARG;
    }

    // 检查连接状态
    if (!handler->is_connected) {
        ESP_LOGW(TAG, "AT command interface not connected");
        return ESP_ERR_INVALID_STATE;
    }

    // 获取互斥锁
    if (xSemaphoreTake(handler->lock, pdMS_TO_TICKS(1000)) != pdTRUE) {
        ESP_LOGE(TAG, "Failed to take mutex");
        return ESP_ERR_TIMEOUT;
    }

    // 设置回调函数和上下文
    handler->callback = callback;
    handler->callback_context = context;

    // 清除之前的响应
    handler->response_received = false;
    memset(handler->rx_buffer, 0, handler->rx_buffer_size);

    ESP_LOGD(TAG, "Sending AT command asynchronously: %s", command);

    // 发送命令
    size_t cmd_len = strlen(command);
    esp_err_t ret = usbh_cdc_write_bytes(handler->cdc_handle, (const uint8_t*)command, cmd_len, pdMS_TO_TICKS(1000));
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to send AT command '%s': %s", command, esp_err_to_name(ret));
        handler->callback = NULL;
        handler->callback_context = NULL;
        xSemaphoreGive(handler->lock);
        return ret;
    }

    // 如果指定了超时时间，则创建超时任务
    if (timeout_ms > 0) {
        // 可以在这里创建一个超时任务来处理超时情况
        // 为简化实现，我们依赖回调机制
    }

    // 释放互斥锁
    xSemaphoreGive(handler->lock);
    return ESP_OK;
}

bool at_command_is_connected(at_command_handler_t handler)
{
    if (!handler) {
        return false;
    }
    return handler->is_connected;
}

esp_err_t at_command_reset(at_command_handler_t handler)
{
    if (!handler) {
        return ESP_ERR_INVALID_ARG;
    }

    // 重新创建USB CDC设备
    if (handler->cdc_handle) {
        usbh_cdc_delete(handler->cdc_handle);
        handler->cdc_handle = NULL;
    }

    // 清除状态
    handler->is_connected = false;
    handler->response_received = false;
    if (handler->rx_buffer) {
        memset(handler->rx_buffer, 0, handler->rx_buffer_size);
    }

    // 重新配置USB CDC设备
    usbh_cdc_device_config_t cdc_config = {
        .vid = 0,
        .pid = 0,
        .itf_num = handler->itf_num,
        .rx_buffer_size = handler->rx_buffer_size,
        .tx_buffer_size = handler->rx_buffer_size, // 使用相同大小
        .cbs = {
            .connect = at_connect_cb,
            .disconnect = at_disconnect_cb,
            .recv_data = at_recv_data_cb,
            .user_data = handler,
        },
    };

    esp_err_t ret = usbh_cdc_create(&cdc_config, &handler->cdc_handle);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to recreate USB CDC device: %s", esp_err_to_name(ret));
        return ret;
    }

    ESP_LOGI(TAG, "AT command handler reset successfully");
    return ESP_OK;
}